MultiplayerEvents = {
    MOVE:"MOVE",
    PLANTBOMB:"PLANTBOMB",
    PLAYERJOIN:"PLAYERJOIN",
    STARTGAME:"STARTGAME",
    REMOVELIFE:"REMOVELIFE",
    TAKEUPGRADE:"TAKEUPGRADE"
};

var interpretJoin = function (JSONmsg) {
    log("JOIN MESSAGE RECIEVED: ");
    log(JSONmsg);

    addJoinedPlayer(JSONmsg.playerUID);
    if (OurGame.isInitator) {
        log("isInitator");
        OurGame.curNrOfPlayers += 1;
        if (OurGame.curNrOfPlayers == OurGame.maxNrOfPlayers) {
            createSTARTButton();
        }
    }
};

var interpretPlant = function (JSONmsg) {
    var index = getElementIndexByTypeAndID(Number(JSONmsg.playerUID), "p");
    if (OurGame.players[index]) {
        if (OurGame.players[index].getID() != OurGame.UID) { // not to plant double bombs
            OurGame.players[index].plantBomb(JSONmsg.bombx, JSONmsg.bomby);
        }
    }
};

var interpretMove = function (JSONmsg) {
    var player = OurGame.players[JSONmsg.i];
    if (player) {
        if (JSONmsg.nr > player.lastRecievedNr){
            player.lastRecievedNr = JSONmsg.nr;
            player.setDesired(JSONmsg.x, JSONmsg.y);
        }
    }
};

var interpretStartGame = function (JSONmsg) {
    log("START GAME MESSAGE RECIEVED: ");
    log(JSONmsg);
    removeLobby();
    addGeneratedUpgrades(JSONmsg.upgrades);
    createMultiplayersAndStart(JSONmsg.players);
};

var interpretRemoveLife = function (JSONmsg) {
    var index = getElementIndexByTypeAndID(Number(JSONmsg.playerUID), "p");
    if (OurGame.players[index]) {
        OurGame.players[index].immortalTimer = 0;
        for (var i = 0; i < JSONmsg.playerLivesAndScores.length; i++){
            index = getElementIndexByTypeAndID(Number(JSONmsg.playerLivesAndScores[i].id), "p");
            if (OurGame.players[index] != undefined) {
                OurGame.players[index].lives = Number(JSONmsg.playerLivesAndScores[i].lives);
                OurGame.players[index].kills = Number(JSONmsg.playerLivesAndScores[i].kills);
                updatePlayerSidebar(OurGame.players[index]);
            }
        }
    }
};

var interpretTakeUpgrade = function(JSONmsg) {
    var index = getElementIndexByTypeAndID(Number(JSONmsg.puid), "p");
    if (OurGame.players[index]) {
        if (OurGame.players[index].addUpgrade(JSONmsg.unum)) {
            level.map[JSONmsg.x][JSONmsg.y] = 'p' + index;
        }
    }
};

function takeUpgrade(player, x, y, upgradeNr) {
    var data = {
        'puid':player.getID(),
        'x':x,
        'y':y,
        'unum':upgradeNr
    };
    if (!channel.trigger("client-" + MultiplayerEvents.TAKEUPGRADE, JSON.stringify(data))) {
        stickyError('An error occured when syncing taken upgrades', "Unknown pusher error occurred when taking upgrade");
    }
}

function getGamesStat(callback) {
    jQuery.ajax({
        url:"/lobby/getGamesStat",
        success:function (data) {
            if (data.status == "FAILURE") {
                stickyError('An error occurred', "ERROR /lobby/getGamesStat: " + data.reason);
            } else {
                if (callback != undefined) {
                    callback(data);
                }
                else {
                    log(data);
                }
            }
        },
        error:function (data) {
            stickyError('An error occurred!', "Error /lobby/getGamesStat: " + data);
        },
        type:"get",
        timeout:30000
    });
}

function markUserOffline() {
    var data = {
        "playerUID":OurGame.UID
    };
    sendData("/user/markUserOffline", JSON.stringify(data));
}

function createOrMarkOnline(success) {
    getFacebookNameById(
        OurGame.UID,
        function(name) {
            var data = {
                "playerUID":OurGame.UID,
                "socketID":OurGame.socketID,
                "name":name
            };
            if (success){
                sendData("/user/createOrMarkOnline", JSON.stringify(data), success);
            } else {
                sendData("/user/createOrMarkOnline", JSON.stringify(data));
            }
        }
    );
}

function createFinalStates() {
    var finalStates = [];
    for (var i = 0; i < OurGame.deadPlayers.length; i++) {
        finalStates.push({"UID":OurGame.deadPlayers[i].id, "score":OurGame.deadPlayers[i].kills});
    }
    var j = getWinningPlayerIndex();
    finalStates.push({"UID":OurGame.players[j].id, "score":OurGame.players[j].kills});
    log(finalStates);
    return finalStates;
}
function getWinningPlayerIndex() {
    for (var i = 0; i < OurGame.players.length; i++) {
        if (OurGame.players[i]) {
            return i;
        }
    }
}
function gameOver() {
    var data = {
        "gameID":OurGame.gameID,
        "finalStates":createFinalStates()
    };
    sendData("/gameOver", JSON.stringify(data));
}

function playerLeftGame(playerUID) {
    var data = {
        "gameID":OurGame.gameID,
        "playerUID":playerUID
    };
    sendData("/playerLeftGame", JSON.stringify(data));
}

function getPlayerLivesAndScores() {
    var lives = [];
    for (var i = 0; i < OurGame.players.length; i++) {
        if (OurGame.players[i]) {
            lives.push({"id":OurGame.players[i].id, "lives":OurGame.players[i].lives, "kills":OurGame.players[i].kills});
        }
    }
    return lives;
}
function removeLife() {
    var data = {
        "gameID":OurGame.gameID,
        "socketID":OurGame.socketID,
        "playerUID":OurGame.UID,
        "playerLivesAndScores":getPlayerLivesAndScores()
    };
    if (!channel.trigger("client-" + MultiplayerEvents.REMOVELIFE, JSON.stringify(data))) {
        stickyError('An error occured when syncing lives and scores!', "FUUUU");
    }
}

function makeMove(player, x, y) {
    var data = {
        "type":"move",
        "i":OurGame.myPlayerIndex,
        "x":player.getPosX() + x,
        "y":player.getPosY() + y,
        "nr":player.nrOfMoves
    };
    PUBNUB.publish({
        channel:OurGame.gameID + "-move",
        message:data
    });
}

function plantBomb(player) {
    var data = {
        "type":"plant",
        "playerUID":OurGame.UID,
        "bombx":player.x,
        "bomby":player.y
    };
    PUBNUB.publish({
        channel:OurGame.gameID + "-move",
        message:data
    });
}

function startGame() {
    $('#startButton').remove(); // remove start button so that user can't press it more than once
    var upgrades = generateUpgrades();
    var data = {
        "gameID":OurGame.gameID,
        "playerUIDs":OurGame.playerUIDs,
        "upgrades":upgrades
    };
    sendData("/startGame", JSON.stringify(data));
}

var registerPlayer = function () {
    var uid = OurGame.UID;
    var gameID = OurGame.gameID;
    var register = {
        "gameID":gameID,
        "playerUID":uid,
        "socketID":OurGame.socketID
    };

    if (!channel.trigger("client-" + MultiplayerEvents.PLAYERJOIN, JSON.stringify(register))) {
        stickyError('An error occured when registering player!', "FUUUU");
    }
};

function checkJoinPermission(gameID) {
    var uid = OurGame.UID;

    OurGame.isInitator = false;
    var register = {
        "gameID":gameID,
        "playerUID":uid
    };

    var success = function (serverAns) {
        if (serverAns.status == "SUCCESS") {
            OurGame.nrOfPlayers = serverAns.nrOfPlayers;
            log("CHECKJOIN");
            log('Server answer: ');
            log(serverAns);

            startGameWaitScreen(serverAns.registeredPlayers, serverAns.itendedPlayers, serverAns.nrOfPlayers);
            initChannel();
        } else {
            stickyError(serverAns.reason, "ERROR checkJoinPermission: " + serverAns.reason);
        }
    };
    sendData("/checkJoinPermission", JSON.stringify(register), success);
}

function initChannel() {

    // LISTEN FOR MESSAGES
    PUBNUB.subscribe({
        channel:OurGame.gameID + "-move", // CONNECT TO THIS CHANNEL.
        restore:true, // STAY CONNECTED, EVEN WHEN BROWSER IS CLOSED
        callback:function (message) { // RECEIVED A MESSAGE.
            if (message.type == "move") {
                if (message.i != OurGame.myPlayerIndex) {
                    interpretMove(message);
                }
            } else {
                interpretPlant(message);
            }
        },
        disconnect:function () {        // LOST CONNECTION.
            log("PUBNUB: Connection Lost. Will auto-reconnect when Online.");
        },
        reconnect:function () {log("PUBNUB: And we're Back!");},

        connect:function () { log("PUBNUB CONNECTED");}
    });

    channel = pusher.subscribe("presence-"+OurGame.gameID.toString());
    channel.bind('pusher:subscription_succeeded', function(members) {
        log("SUBSCRIPTION SUCCEEDED");
        log(members.count);

        members.each(function(member) {
            log(member.id);
            log(member.info.name);
            log(to_utf8(member.info.name));
            if (!OurGame.playerName) OurGame.playerName = to_utf8(member.info.name);
        });

        registerPlayer();
    });
    channel.bind('pusher:member_removed', function(member) {
        log("REMOVED: " + member.id);
        var name = to_utf8(member.info.name);
        log(name);
        if (member.info.isInitator){
            error("Game initator (" + name + ") left the game! Terminating game in 5s!");
            setTimeout(refreshPage, 5000);
        }else{
            warning(name + " left the game!");
        }
        addLeftPlayer(member.id);
        if (OurGame.isInitator){playerLeftGame(member.id);}

    });
    channel.bind("client-"+MultiplayerEvents.PLANTBOMB, interpretPlant);
    channel.bind("client-"+MultiplayerEvents.PLAYERJOIN, interpretJoin);
    channel.bind("client-"+MultiplayerEvents.STARTGAME, interpretStartGame);
    channel.bind("client-"+MultiplayerEvents.REMOVELIFE, interpretRemoveLife);
    channel.bind("client-"+MultiplayerEvents.TAKEUPGRADE, interpretTakeUpgrade);
}

function sendData(path, myData, successFunction, errorFunction) {
    jQuery.ajax({
        url:path,
        data:{"data":myData},
        success:successFunction || function (data) {
            if (data.status == "FAILURE") {
                alert("ERROR: " + data.reason);
            }
        },
        error:errorFunction || function (data) {
            log(data);
        },
        type:"post",
        timeout:30000
    });
}